package atag.runtime.ln.neighborhoodDefs;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import atag.runtime.ln.nodeAttributes.DoubleAttribute;
import atag.runtime.ln.nodeAttributes.NodeAttribute;

/**
 * An atomic predicate specifying a constraint on the value of an double
 * attribute. The possible constraints are defined as numeric constants in this
 * class.
 */
public class DoubleSimplePredicate extends Predicate {

	// Possible comparators
	public static final int EQUAL = 0;

	public static final int LESS_THAN = 1;

	public static final int GREATER_THAN = 2;

	public static final int LESS_EQUAL_THAN = 3;

	public static final int GREATER_EQUAL_THAN = 4;

	// Predicate data
	private String attrName;

	private int comparator;

	private double value;

	/**
	 * Creates an instance of this predicate.
	 * 
	 * @param attrName the name of the attribute the predicate refers to.
	 * @param comparator the constraint selected.
	 * @param value the double value to compare the attribute against.
	 */
	public DoubleSimplePredicate(String attrName, int comparator, double value) {
		this.attrName = attrName;
		this.comparator = comparator;
		this.value = value;
	}

	/**
	 * @see polimi.ln.neighborhoodDefs.AtomicPredicate#matches(polimi.ln.nodeAttributes.NodeAttribute)
	 */
	public boolean matches(NodeAttribute attr) {

		if (!(attr instanceof DoubleAttribute))
			return false;

		if (!attr.getKey().equals(attrName))
			return false;

		double attrValue = ((Double) attr.getValue()).doubleValue();
		switch (comparator) {

		case EQUAL:
			return (attrValue == value);
		case LESS_THAN:
			return (attrValue < value);
		case GREATER_THAN:
			return (attrValue > value);
		case LESS_EQUAL_THAN:
			return (attrValue <= value);
		case GREATER_EQUAL_THAN:
			return (attrValue >= value);
		default:
			return false;
		}
	}

	public String toString() {

		String msg = "DoubleSimple predicate for attribute " + attrName + " ";

		switch (comparator) {

		case EQUAL:
			msg = msg.concat("=");
			break;
		case LESS_THAN:
			msg = msg.concat("<");
			break;
		case GREATER_THAN:
			msg = msg.concat(">");
			break;
		case LESS_EQUAL_THAN:
			msg = msg.concat("=<");
			break;
		case GREATER_EQUAL_THAN:
			msg = msg.concat("=>");
			break;
		default:
			msg = msg.concat("UNKNOWN");
			break;
		}

		return msg.concat(" " + value);
	}
	
	public DataOutput serialize(DataOutput dg) throws IOException {

		dg.writeByte(Predicate.DOUBLE_SIMPLE);
		dg.writeUTF(attrName);
		dg.writeInt(comparator);
		dg.writeDouble(value);

		return dg;
	}
	
	public static Predicate deserialize(DataInput dg) throws IOException {
		
		String serializedNameStr = dg.readUTF();
		int comparator = dg.readInt();
		double value = dg.readDouble();
		
		return new DoubleSimplePredicate(serializedNameStr, comparator, value);
	}

}
